package com.ruoyi.system.service.impl;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.config.GeoConfig;
import com.ruoyi.common.config.PersonPosition;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.JobCloseEnum;
import com.ruoyi.common.enums.YnStatusEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.domain.bill.JobPersonnel;
import com.ruoyi.system.entity.PersonnelArchives;
import com.ruoyi.system.entity.SysActing;
import com.ruoyi.system.mapper.AppCreateJobBillMapper;
import com.ruoyi.system.mapper.JobPlanBillDeclareMapper;
import com.ruoyi.system.mapper.PersonnelArchivesMapper;
import com.ruoyi.system.mapper.TemporaryStaffAccountMapper;
import com.ruoyi.system.service.JobPlanBillDeclareOperateService;
import com.ruoyi.system.service.JobPlanBillDeclareService;
import com.ruoyi.system.service.SysActingService;
import com.ruoyi.system.services.EnclosureServices;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 作业计划 - 申报(JobPlanBillDeclare)表服务实现类
 *
 * @since 2022-11-23 09:20:09
 */
@Slf4j
@Service("jobPlanBillDeclareService")
public class JobPlanBillDeclareServiceImpl implements JobPlanBillDeclareService {

    @Autowired
    private RedisCache redisCache;
    @Autowired
    private SysActingService sysActingService;
    @Autowired
    private EnclosureServices enclosureServices;
    @Autowired
    private JobPlanBillDeclareMapper jobPlanBillDeclareDao;
    @Resource
    private AppCreateJobBillMapper appCreateJobBillMapper;
    @Autowired
    private PersonnelArchivesMapper personnelArchivesMapper;
    @Autowired
    private TemporaryStaffAccountMapper temporaryStaffAccountMapper;

    /**
     * 服务对象
     */
    @Resource
    private JobPlanBillDeclareOperateService jobPlanBillDeclareOperateService;

    /**
     * 通过ID查询单条数据
     *
     * @return 实例对象
     */
    @Override
    public JobPlanBillDeclare queryById(Integer id) {
        return this.jobPlanBillDeclareDao.queryById(id);
    }

    /**
     * 分页查询
     *
     * @return 查询结果
     */
    @Override
    public Page<JobPlanBillDeclare> queryByPage(JobPlanBillDeclare jobPlanBillDeclare, PageRequest pageRequest) {
        long total = this.jobPlanBillDeclareDao.count(jobPlanBillDeclare);
        return new PageImpl<>(this.jobPlanBillDeclareDao.queryAllByLimit(jobPlanBillDeclare, pageRequest), pageRequest, total);
    }

    /**
     * 根据绘制围栏ID, 查询作业计划
     * @param JobPlanBillDeclare
     * @return
     */
    @Override
    public JobPlanBillDeclare selectByEnclosureId(JobPlanBillDeclare JobPlanBillDeclare) {
        List<JobPlanBillDeclare> list = jobPlanBillDeclareDao.queryAll(JobPlanBillDeclare);
        return StringUtils.isNotEmpty(list) ? list.get(0) : null;
    }

    /**
     * 查询列表
     *
     * @param jobPlanBillDeclare 参数
     * @return 结果
     */
    @Override
    public List<JobPlanBillDeclare> queryAll(JobPlanBillDeclare jobPlanBillDeclare) {
        jobPlanBillDeclare.setYn(YnStatusEnum.Y.getCode());
        List<JobPlanBillDeclare> jobPlanBillDeclares = jobPlanBillDeclareDao.queryAll(jobPlanBillDeclare);
        if (CollectionUtils.isEmpty(jobPlanBillDeclares)) {
            return new ArrayList<>();
        }

        boolean flag = false;
        List<String> billNumbers = jobPlanBillDeclares.stream().map(JobPlanBillDeclare::getBillNumber).collect(Collectors.toList());
        List<AppCreateJobBill> appCreateJobBills = appCreateJobBillMapper.queryInPtw(billNumbers);
        if (CollectionUtils.isEmpty(appCreateJobBills)) {
            flag = true;
        }

        Map<String, List<AppCreateJobBill>> listMap = appCreateJobBills.stream().collect(Collectors.groupingBy(AppCreateJobBill::getPtw));
        for (JobPlanBillDeclare var : jobPlanBillDeclares) {
            JobPlanBillDeclareOperate jobPlanBillDeclareOperate = new JobPlanBillDeclareOperate();
            jobPlanBillDeclareOperate.setPid(var.getId());
            List<JobPlanBillDeclareOperate> jobPlanBillDeclareOperates = jobPlanBillDeclareOperateService.queryAll(jobPlanBillDeclareOperate);

            if (!CollectionUtils.isEmpty(jobPlanBillDeclareOperates)) {
                Map<Integer, List<JobPlanBillDeclareOperate>> collect = jobPlanBillDeclareOperates.stream().collect(Collectors.groupingBy(JobPlanBillDeclareOperate::getPid));
                List<JobPlanBillDeclareOperate> planBillDeclareOperates = collect.get(var.getId());
                if (!CollectionUtils.isEmpty(planBillDeclareOperates)) {

                    System.out.println(JSON.toJSON(planBillDeclareOperates));

                    JobPlanBillDeclareOperate declareOperate = planBillDeclareOperates.stream()
                            .sorted(Comparator.comparing(JobPlanBillDeclareOperate::getCreatedDate)
                                    .reversed())
                            .collect(Collectors.toList())
                            .stream()
                            .findFirst()
                            .orElse(new JobPlanBillDeclareOperate());

                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    String format = simpleDateFormat.format(declareOperate.getCreatedDate());
                    var.setOperateDate(format);
                    if (declareOperate.getCurrentStatus().equals(YnStatusEnum.Y.getCode())) {
                        var.setOperateStatus(YnStatusEnum.Y.getCode());
                    }
                }
            }

            if (flag) {
                var.setCancel(true);
                continue;
            }
            Date date = new Date();
            String endDate = var.getJobPlanEndDate() + " " + var.getJobPlanEndTime();
            boolean after = date.after(DateUtils.parseDate(endDate));
            if (!after) {
                var.setCancel(false);
                continue;
            }
            if (listMap.containsKey(var.getBillNumber())) {
                var.setCancel(false);
                continue;
            }
            var.setCancel(true);
        }

        return jobPlanBillDeclares;
    }

    /**
     * 新增数据
     *
     * @param jobPlanBillDeclare 实例对象
     * @return 实例对象
     */
    @Override
    public JobPlanBillDeclare insert(JobPlanBillDeclare jobPlanBillDeclare) {
        String number = "";
        //票据类型 + 时间 + 序号
        String key = jobPlanBillDeclare.getBillType().trim();
        SimpleDateFormat tempDate = new SimpleDateFormat("yyyyMMdd");
        String datetime = tempDate.format(new Date());
        if (redisCache.hasKey(key + datetime)) {
            Object cacheObject = redisCache.getCacheObject(key + datetime);
            int object = (Integer) cacheObject;
            int i = object++;
            number = key + "-" + datetime + "-" + (object);
            redisCache.setCacheObject(key + datetime, object);
        } else {
            number = key + "-" + datetime + "-" + 1;
            redisCache.setCacheObject(key + datetime, 1);
        }

        //设置票据号
        jobPlanBillDeclare.setBillNumber(number);
        jobPlanBillDeclare.setCreatedBy(SecurityUtils.getLoginUser().getUsername());
        jobPlanBillDeclare.setCreatedDate(new Date());
        jobPlanBillDeclare.setYn(YnStatusEnum.Y.getCode());
        int insert = this.jobPlanBillDeclareDao.insert(jobPlanBillDeclare);

        //待办任务,申报成功,需要通知待审核人员
        if (insert > 0) {
            //根据票据号查询;
            JobPlanBillDeclare jobPlanBillDeclareQuery = new JobPlanBillDeclare();
            jobPlanBillDeclareQuery.setBillNumber(number);
            List<JobPlanBillDeclare> jobPlanBillDeclares = jobPlanBillDeclareDao.queryAll(jobPlanBillDeclareQuery);
            if (CollectionUtils.isEmpty(jobPlanBillDeclares)) {
                return jobPlanBillDeclare;
            }

            SysActing sysActing = new SysActing();
            //标题名称
            sysActing.setTitleName("作业票");
            //标题类型
            sysActing.setTitleType("作业票申报");
            //标题详情 (票据号)
            sysActing.setTitleInfo(jobPlanBillDeclare.getBillNumber());
            //发起人ID (申请人ID)
            if (!StringUtils.isEmpty(jobPlanBillDeclare.getApplyPeopleId())) {
                sysActing.setOriginatorId(Integer.valueOf(jobPlanBillDeclare.getApplyPeopleId()));
            }
            //发起人名称 (申请人名称)
            sysActing.setOriginatorName(jobPlanBillDeclare.getApplyPeople());
            //执行人id (现场批准人ID)
            if (!StringUtils.isEmpty(jobPlanBillDeclare.getApprovedById())) {
                sysActing.setExecutorId(Integer.valueOf(jobPlanBillDeclare.getApprovedById()));
            }
            //执行人名称 (现场批准人)
            sysActing.setExecutorName(jobPlanBillDeclare.getApprovedBy());
            //元数据ID (更优取值,直接新增完票据号返回)
            int i = null == (jobPlanBillDeclares.stream().findFirst().orElse(null)) ? 0 : jobPlanBillDeclares.stream().findFirst().orElse(null).getId();
            sysActing.setSourceId(i);

            log.info("申报成功,需要通知待审核人员:{}", JSON.toJSON(sysActing));
            sysActingService.insert(sysActing);

            /** 同步报警围栏 **/
            createEnclosure(jobPlanBillDeclare);

            /*
                后期需要考虑 作业票成功,加入待办失败。
                解决方案1: 事务控制,同时回滚。
                解决方案2: 作业票依然成功,待办加入异常日志 （日志|数据异常）
             */
        }

        return jobPlanBillDeclare;
    }

    public int updateAboutGeoWarn(Long areaId, Integer enclosureId, Integer ruleId, Integer id) {
        return jobPlanBillDeclareDao.updateAboutGeoWarn(areaId, enclosureId, ruleId, id);
    }

    /**
     * 修改数据
     *
     * @param jobPlanBillDeclare 实例对象
     * @return 实例对象
     */
    @Override
    public JobPlanBillDeclare update(JobPlanBillDeclare jobPlanBillDeclare) {
        JobPlanBillDeclare oldJobPlan = this.jobPlanBillDeclareDao.queryById(jobPlanBillDeclare.getId());
        String oldLatitude  = oldJobPlan.getLatitude();
        String oldLongitude  = oldJobPlan.getLongitude();
        Integer oldMaxPersonNum = oldJobPlan.getMaxPersonNum();
        this.jobPlanBillDeclareDao.update(jobPlanBillDeclare);
        /** 同步报警围栏 **/
        String newLatitude  = jobPlanBillDeclare.getLatitude();
        String newLongitude  = jobPlanBillDeclare.getLongitude();
        Integer newMaxPersonNum = jobPlanBillDeclare.getMaxPersonNum();
        Long areaId = oldJobPlan.getAreaId();
        Integer ruleId = oldJobPlan.getRuleId();
        Integer enclosureId = oldJobPlan.getEnclosureId();

        if (StringUtils.isEmpty(newLatitude) || StringUtils.isEmpty(newLongitude) || newMaxPersonNum==null) {
            // 删除报警规则 和 作业围栏
            enclosureServices.delEnclosure(enclosureId);
            enclosureServices.delRule(ruleId);
        } else if ( !newLatitude.equals(oldLatitude) || !newLongitude.equals(oldLongitude) ) {
            // 删除之前的围栏， 创建新围栏
            enclosureServices.delEnclosure(enclosureId);
            enclosureServices.delRule(ruleId);
            createEnclosure(jobPlanBillDeclare);
        } else if (oldMaxPersonNum==null || oldMaxPersonNum.intValue() != newMaxPersonNum.intValue()) {
            enclosureServices.delRule(ruleId);
            // 新增报警规则
            if (enclosureId!=null && newMaxPersonNum>0) {
                ruleId = enclosureServices.addRule(jobPlanBillDeclare.getBillNumber(), enclosureId, newMaxPersonNum);
            }
            if (ruleId!=null) {
                updateAboutGeoWarn(areaId, enclosureId, ruleId, jobPlanBillDeclare.getId());
            }
        }

        //判断作业票是否关闭;
        if (null != jobPlanBillDeclare.getClose()) {
            if (jobPlanBillDeclare.getClose().equals(JobCloseEnum.YES_CLOSE.getCode())) {
                SysActing sysActing = new SysActing();
                //标题名称
                sysActing.setTitleName("作业票");
                //标题类型
                sysActing.setTitleType("作业票关闭");
                //标题详情 (票据号)
                sysActing.setTitleInfo(jobPlanBillDeclare.getBillNumber());
                log.info("申报关闭,需要通知待审核人员:{}", JSON.toJSON(sysActing));

                sysActingService.insert(sysActing);
            }
        }

//        String drawArea2 = jobPlanBillDeclare.getDrawArea2();
//        if (StringUtils.isNotEmpty(drawArea2)) {
//            // 上报围栏和报警事件
//            enclosureAdd(jobPlanBillDeclare.getDrawArea2(), jobPlanBillDeclare.getBillNumber(), 321L);
//            addRule(jobPlanBillDeclare.getBillNumber(), 123, 100);
//        }

        return this.queryById(jobPlanBillDeclare.getId());
    }

    public boolean createEnclosure(JobPlanBillDeclare jobPlanBillDeclare) {
        /** 同步报警围栏 **/
        String drawArea2 = jobPlanBillDeclare.getDrawArea2();
        if (StringUtils.isNotEmpty(drawArea2)) {
            Long areaId = enclosureServices.getAreaId();
            String billNumber = jobPlanBillDeclare.getBillNumber();
            Integer enclosureId = enclosureServices.addEnclosure(drawArea2, billNumber, areaId);
//            Integer enclosureId = getEenclosureId(areaId+"", "作业票围栏-" + billNumber);
            Integer maxPersonNum = jobPlanBillDeclare.getMaxPersonNum();
            Integer ruleId = null;
            if (enclosureId!=null && maxPersonNum!=null && maxPersonNum>0) {
                ruleId = enclosureServices.addRule(jobPlanBillDeclare.getBillNumber(), enclosureId, maxPersonNum);
            }
            if (enclosureId!=null) {
                updateAboutGeoWarn(areaId, enclosureId, ruleId, jobPlanBillDeclare.getId());
            }
        }

        return true;
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Integer id) {
        //查询当前申报;
        JobPlanBillDeclare jobPlanBillDeclare = jobPlanBillDeclareDao.queryById(id);
        if (null == jobPlanBillDeclare) {
            return false;
        }
        if (StringUtils.isEmpty(jobPlanBillDeclare.getBillNumber())) {
            return false;
        }

        //根据申报查询是否有正常的作业票
        List<String> ptwList = Collections.singletonList(jobPlanBillDeclare.getBillNumber());
        List<AppCreateJobBill> appCreateJobBills = appCreateJobBillMapper.queryInPtw(ptwList);
        if (!CollectionUtils.isEmpty(appCreateJobBills)) {
            throw new ServiceException("当前申报下存在正在使用作业票,无法完成");
        }

        //将申报逻辑删除
        JobPlanBillDeclare jobPlanBillDeclareUpd = new JobPlanBillDeclare();
        jobPlanBillDeclareUpd.setId(id);
        jobPlanBillDeclareUpd.setYn(YnStatusEnum.N.getCode());

        jobPlanBillDeclareDao.update(jobPlanBillDeclareUpd);

        return true;
    }

    /**
     * 查询作业人员
     *
     * @param jobPersonnel 参数
     * @return 结果
     */
    @Override
    public List<JobPersonnel> queryJobPersonnel(JobPersonnel jobPersonnel) {
        List<JobPersonnel> jobPersonnels = new ArrayList<>();
        //人员档案
        PersonnelArchives personnelArchives = new PersonnelArchives();
        List<PersonnelArchives> personnelArchivesList = personnelArchivesMapper.queryAll(personnelArchives);
        if (!CollectionUtils.isEmpty(personnelArchivesList)) {
            personnelArchivesList.forEach(personnelArchivesResp -> {
                JobPersonnel jobPersonnelResp = new JobPersonnel();
                jobPersonnelResp.setPersonnelType(JobPersonnel.JobPersonnelTypeEnum.FORMAL.getCode().toString());
                jobPersonnelResp.setPersonnelId(personnelArchivesResp.getId());
                jobPersonnelResp.setPersonnelName(personnelArchivesResp.getName());
                jobPersonnels.add(jobPersonnelResp);
            });
        }
        //临时施工人员
        TemporaryStaffAccount temporaryStaffAccount = new TemporaryStaffAccount();
        List<TemporaryStaffAccount> temporaryStaffAccounts = temporaryStaffAccountMapper.queryAll(temporaryStaffAccount);
        if (!CollectionUtils.isEmpty(temporaryStaffAccounts)) {
            temporaryStaffAccounts.forEach(temporaryStaffAccountResp -> {
                JobPersonnel jobPersonnelResp = new JobPersonnel();
                jobPersonnelResp.setPersonnelType(JobPersonnel.JobPersonnelTypeEnum.TEMPORARY.getCode().toString());
                jobPersonnelResp.setPersonnelId(temporaryStaffAccountResp.getId());
                jobPersonnelResp.setPersonnelName(temporaryStaffAccountResp.getName());
                jobPersonnels.add(jobPersonnelResp);
            });
        }
        return jobPersonnels;
    }

    @Override
    public List<JobPlanBillDeclare> queryJobTimeout(JobPlanBillDeclare jobPlanBillDeclare) {
        return this.jobPlanBillDeclareDao.queryJobTimeout(jobPlanBillDeclare);
    }

    @Override
    public JobPlanBillDeclare renewal(JobPlanBillDeclareRenewal jobPlanBillDeclareRenewal) {
        JobPlanBillDeclare jobPlanBillDeclare = jobPlanBillDeclareDao.queryById(jobPlanBillDeclareRenewal.getId());

        String number = "";
        //票据类型 + 时间 + 序号
        String key = jobPlanBillDeclare.getBillType().trim();
        SimpleDateFormat tempDate = new SimpleDateFormat("yyyyMMdd");
        String datetime = tempDate.format(new Date());
        if (redisCache.hasKey(key + datetime)) {
            Object cacheObject = redisCache.getCacheObject(key + datetime);
            int object = (Integer) cacheObject;
            int i = object++;
            number = key + "-" + datetime + "-" + (object);
            redisCache.setCacheObject(key + datetime, object);
        } else {
            number = key + "-" + datetime + "-" + 1;
            redisCache.setCacheObject(key + datetime, 1);
        }

        //设置票据号
        jobPlanBillDeclare.setBillNumber(number);
        //续签开始时间
        jobPlanBillDeclare.setJobPlanStartDate(jobPlanBillDeclareRenewal.getJobPlanStartDate());
        jobPlanBillDeclare.setJobPlanStartTime(jobPlanBillDeclareRenewal.getJobPlanStartTime());
        //续签结束时间
        jobPlanBillDeclare.setJobPlanEndDate(jobPlanBillDeclareRenewal.getJobPlanEndDate());
        jobPlanBillDeclare.setJobPlanEndTime(jobPlanBillDeclareRenewal.getJobPlanEndTime());
        //申报类型
        jobPlanBillDeclare.setDeclareType("续签");
        //时间
        jobPlanBillDeclare.setCreatedDate(new Date());
        this.jobPlanBillDeclareDao.insert(jobPlanBillDeclare);

        return jobPlanBillDeclare;
    }


}
